﻿using Xunit;

namespace Unity.String.Tests.Number
{
    public class BigIntegerTest
    {
        [Fact]
        public void AddTest()
        {
            System.Number.BigInteger testAddResultBigInteger = new System.Number.BigInteger();
            Assert.True(testAddResultBigInteger.IsZero());
            testAddResultBigInteger.Add(1);
            Assert.True(testAddResultBigInteger.IsOne());

            System.Number.BigInteger testLeftBigInteger = new System.Number.BigInteger();
            testLeftBigInteger.Add(2);
            System.Number.BigInteger testRightBigInteger = new System.Number.BigInteger();
            testRightBigInteger.Add(4);

            System.Number.BigInteger.Add(ref testLeftBigInteger, ref testRightBigInteger, out testAddResultBigInteger);
            Assert.Equal(6UL, testAddResultBigInteger.ToUInt64());
        }

        [Fact]
        public void MultiplyTest()
        {
            System.Number.BigInteger testMultiplyOriginalValueBigInteger = new System.Number.BigInteger();
            System.Number.BigInteger testMultiplyBigInteger = new System.Number.BigInteger();
            testMultiplyOriginalValueBigInteger.Add(2);
            testMultiplyBigInteger.Add(3);
            System.Number.BigInteger.Multiply(ref testMultiplyOriginalValueBigInteger, ref testMultiplyBigInteger, 
                out var testMultiplyResultBigInteger);
            System.Number.BigInteger testMultiplyResultValueBigInteger = new System.Number.BigInteger();
            testMultiplyResultValueBigInteger.Add(6);
            Assert.Equal(0, System.Number.BigInteger.Compare(ref testMultiplyResultValueBigInteger, ref testMultiplyResultBigInteger));
        }

        [Fact]
        public void DivRemTest()
        {
            System.Number.BigInteger testDivRemDividendValueBigInteger = new System.Number.BigInteger();
            System.Number.BigInteger testDivRemDivisorValueBigInteger = new System.Number.BigInteger();
            testDivRemDividendValueBigInteger.Add(9);
            testDivRemDivisorValueBigInteger.Add(4);
            System.Number.BigInteger.DivRem(
                ref testDivRemDividendValueBigInteger, 
                ref testDivRemDivisorValueBigInteger, 
                out var testDivRemQuotientValueBigInteger, 
                out var testDivRemRemainderValueBigInteger);
            Assert.Equal(2U, testDivRemQuotientValueBigInteger.ToUInt64());
            Assert.Equal(1U, testDivRemRemainderValueBigInteger.ToUInt64());
            
            System.Number.BigInteger testDivRemDividendBigValueBigInteger = new System.Number.BigInteger();
            System.Number.BigInteger testDivRemDivisorBigValueBigInteger = new System.Number.BigInteger();
            
            testDivRemDividendBigValueBigInteger.Add(7684298);
            testDivRemDivisorBigValueBigInteger.Add(431);
            System.Number.BigInteger.DivRem(
                ref testDivRemDividendBigValueBigInteger, 
                ref testDivRemDivisorBigValueBigInteger, 
                out testDivRemQuotientValueBigInteger, 
                out testDivRemRemainderValueBigInteger);
            Assert.Equal(17828U, testDivRemQuotientValueBigInteger.ToUInt64());
            Assert.Equal(430U, testDivRemRemainderValueBigInteger.ToUInt64());
            
            System.Number.BigInteger testDivRemDividendZeroValueBigInteger = new System.Number.BigInteger();
            
            System.Number.BigInteger.DivRem(
                ref testDivRemDividendZeroValueBigInteger, 
                ref testDivRemDivisorValueBigInteger, 
                out testDivRemQuotientValueBigInteger, 
                out testDivRemRemainderValueBigInteger);
            
        }

        [Fact]
        public void HeuristicDivideTest()
        {
            System.Number.BigInteger testHeuristicDividendValueBigInteger = new System.Number.BigInteger();
            System.Number.BigInteger testHeuristicDivisorValueBigInteger = new System.Number.BigInteger();
            
            testHeuristicDividendValueBigInteger.Add(7684298);
            testHeuristicDivisorValueBigInteger.Add(431);
            uint heuristicDivide = System.Number.BigInteger.HeuristicDivide(
                ref testHeuristicDividendValueBigInteger, 
                ref testHeuristicDivisorValueBigInteger);
            Assert.Equal(17788U, heuristicDivide);
            
            System.Number.BigInteger testHeuristicDividendBigValueBigInteger = new System.Number.BigInteger();
            System.Number.BigInteger testHeuristicDivisorBigValueBigInteger = new System.Number.BigInteger();
            
            testHeuristicDividendBigValueBigInteger.Add(431);
            testHeuristicDivisorBigValueBigInteger.Add(7684298);
            uint heuristicDivideBig = System.Number.BigInteger.HeuristicDivide(
                ref testHeuristicDividendBigValueBigInteger, 
                ref testHeuristicDivisorBigValueBigInteger);
            Assert.Equal(0UL, heuristicDivideBig); 
        }

        [Fact]
        public void CompareTest()
        {
            System.Number.BigInteger testBigIntegerLeftValue = 
                new System.Number.BigInteger();
            System.Number.BigInteger testBigIntegerRightValue = 
                new System.Number.BigInteger();
            Assert.Equal(0, System.Number.BigInteger.Compare(
                ref testBigIntegerLeftValue, ref testBigIntegerRightValue) );
            testBigIntegerLeftValue.Add(2);            
            Assert.Equal(1, System.Number.BigInteger.Compare(
                ref testBigIntegerLeftValue, ref testBigIntegerRightValue) );
            testBigIntegerRightValue.Add(4);
            Assert.Equal(-1, System.Number.BigInteger.Compare(
                ref testBigIntegerLeftValue, ref testBigIntegerRightValue) );
        }
        
        [Fact]
        public void CountSignificantBitsTest()
        {
            Assert.Equal(7UL, System.Number.BigInteger.CountSignificantBits(123U));
            Assert.Equal(14UL, System.Number.BigInteger.CountSignificantBits(12345UL));
            System.Number.BigInteger testBigIntegerValue = 
                new System.Number.BigInteger();
            Assert.Equal(0U, System.Number.BigInteger.CountSignificantBits(ref testBigIntegerValue));
            testBigIntegerValue.Add(123456);
            Assert.Equal(17U, System.Number.BigInteger.CountSignificantBits(ref testBigIntegerValue));
        }
    }
}